﻿using System.ComponentModel;
using System.Runtime.InteropServices;
using System;
using System.DirectoryServices;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Security;

namespace Marbles.Data.LDAP
{
    public class LDAPUser
    {

        public Guid ObjectGuid { get { return this._objectGuid; } }
        public string[] ObjectClass { get { return this._ObjectClass.ToArray(); } }
        public string[] Groups { get { return this._memberOf.ToArray(); } }
        public string Username { get { return this._Username; } }
        public string DistinguishedName { get { return this._distinguishedName; } }
        public string Email { get { return this._email; } }
        public string Comments { get { return this._Comments; } }
        public string Firstname { get { return this._Firstname; } }
        public string Lastname { get { return this._Lastname; } }
        public string Fullname { get { return this._Fullname; } }
        public DateTime DateCreated { get { return this._DateCreated; } }
        public DateTime LastLogon { get { return this._LastLogon; } }
        public DateTime PasswordLastSet { get { return this._PasswordLastSet; } }
        public DateTime LastChanged { get { return this._LastChanged; } }
        public DateTime LastBadPassword { get { return this._LastBadPassword; } }
        public bool Enabled { get { return this._Enabled; } }
        public bool LockedOut { get { return this._LockedOut; } }

        private List<string> _ObjectClass = null;
        private List<string> _memberOf = null;
        private Guid _objectGuid = Guid.Empty;
        private string _Username = string.Empty;
        private string _distinguishedName = string.Empty;
        private string _email = string.Empty;
        private string _Comments = string.Empty;
        private string _Firstname = string.Empty;
        private string _Lastname = string.Empty;
        private string _Fullname = string.Empty;
        private DateTime _LastChanged = DateTime.MinValue;
        private DateTime _DateCreated = DateTime.MinValue;
        private DateTime _LastLogon = DateTime.MinValue;
        private DateTime _PasswordLastSet = DateTime.MinValue;
        private DateTime _LastBadPassword = DateTime.MinValue;
        private bool _Enabled = false;
        private bool _LockedOut = false;

        public LDAPUser(PropertyCollection Properties, Guid Guid)
        {
            int userAccountControl = Convert.ToInt32(InternalGetProperty("userAccountControl", Properties).ToString());
            this._objectGuid = Guid;
            this._LastChanged = ConvertToDateTime("whenChanged", Properties);
            this._ObjectClass = new List<string>();
            this._memberOf = new List<string>();
            this._Username = GetProperty("sAMAccountName", Properties);
            this._distinguishedName = GetProperty("distinguishedName", Properties);
            this._email = GetProperty("userPrincipalName", Properties);
            this._Comments = GetProperty("cn", Properties);
            this._Firstname = GetProperty("givenName", Properties);
            this._Lastname = GetProperty("sn", Properties);
            this._Fullname = GetProperty("name", Properties);
            this._DateCreated = ConvertToDateTime("whenCreated", Properties);
            this._LastLogon = ConvertToDateTime1("lastLogon", Properties);
            this._PasswordLastSet = ConvertToDateTime1("pwdLastSet", Properties);
            this._LastBadPassword = ConvertToDateTime1("badPasswordTime", Properties);
            this._ObjectClass = InternalGetProperty1("ObjectClass", Properties);
            this._memberOf = InternalGetProperty1("memberOf", Properties);
            this._Enabled = ((userAccountControl & ADS_UF_ACCOUNTDISABLE) == 0);
            this._LockedOut = !((userAccountControl & ADS_UF_LOCKOUT) == 0);
        }

        private DateTime ConvertToDateTime(string Key, PropertyCollection Result)
        {
            string value = InternalGetProperty(Key, Result).ToString();
            DateTime value1 = Convert.ToDateTime(value);
            return value1;
        }

        private DateTime ConvertToDateTime1(string Key, PropertyCollection Result)
        {

            IADsLargeInteger value = (IADsLargeInteger)InternalGetProperty(Key, Result);

            if (value != null)
            {
                long filetime = value.HighPart * 4294967296 + value.LowPart;
                return DateTime.FromFileTime(filetime);
            }

            return DateTime.MinValue;
        }

        private object InternalGetProperty(string key, PropertyCollection Result)
        {
            foreach (string s in Result.PropertyNames)
            {
                if (s.ToLower() == key.ToLower())
                {
                    PropertyValueCollection value = Result[s];
                    if (value.Count > 0)
                    {
                        if (value[0] != null) { return value[0]; }
                        return null;
                    }
                }
            }

            return null;
        }

        private List<string> InternalGetProperty1(string key, PropertyCollection Result)
        {
            List<string> items = new List<string>();
            foreach (string s in Result.PropertyNames)
            {
                if (s.ToLower() == key.ToLower())
                {
                    PropertyValueCollection value = Result[s];
                    if (value.Count > 0)
                    {
                        for (int i = 0; i < value.Count; i++)
                        {
                            items.Add(value[i].ToString());
                        }
                    }
                }
            }

            return items;
        }

        private string GetProperty(string key, PropertyCollection Result)
        {
            object value = InternalGetProperty(key, Result);
            if (value == null) { return string.Empty; }
            return value.ToString();
        }

        [ComImport]
        [Guid("9068270B-0939-11D1-8BE1-00C04FD8D503")]
        [InterfaceType(ComInterfaceType.InterfaceIsDual)]
        internal interface IADsLargeInteger
        {
            [DispId(0x00000002)]
            int HighPart { get; set; }
            [DispId(0x00000003)]
            int LowPart { get; set; }
        }

        private const int ADS_UF_SCRIPT = 0x0001;
        private const int ADS_UF_ACCOUNTDISABLE = 0x0002;
        private const int ADS_UF_HOMEDIR_REQUIRED = 0x0008;
        private const int ADS_UF_LOCKOUT = 0x0010;
        private const int ADS_UF_PASSWD_NOTREQD = 0x0020;
        private const int ADS_UF_PASSWD_CANT_CHANGE = 0x0040;
        private const int ADS_UF_ENCRYPTED_TEXT_PWD_ALLOWED = 0x0080;
        private const int ADS_UF_TEMP_DUPLICATE_ACCOUNT = 0x0100;
        private const int ADS_UF_NORMAL_ACCOUNT = 0x0200;
        private const int ADS_UF_INTERDOMAIN_TRUST_ACCOUNT = 0x0800;
        private const int ADS_UF_WORKSTATION_TRUST_ACCOUNT = 0x1000;
        private const int ADS_UF_SERVER_TRUST_ACCOUNT = 0x2000;
        private const int ADS_UF_DONT_EXPIRE_PASSWORD = 0x10000;
        private const int ADS_UF_MNS_LOGON_ACCOUNT = 0x20000;
        private const int ADS_UF_SMARTCARD_REQUIRED = 0x40000;
        private const int ADS_UF_TRUSTED_FOR_DELEGATION = 0x80000;
        private const int ADS_UF_NOT_DELEGATED = 0x100000;
        private const int ADS_UF_USE_DES_KEY_ONLY = 0x200000;
        private const int ADS_UF_DONT_REQ_PREAUTH = 0x400000;
        private const int ADS_UF_PASSWORD_EXPIRED = 0x800000;
        private const int ADS_UF_TRUSTED_TO_AUTH_FOR_DELEGATION = 0x1000000;

    }
}
